package com.uinnova.product.eam.service.cj.service.impl;

import cn.hutool.core.collection.ListUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.binary.core.exception.BinaryException;
import com.binary.core.util.BinaryUtils;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.util.EamUtil;
import com.uinnova.product.eam.comm.exception.BusinessException;
import com.uinnova.product.eam.comm.model.es.ArchReview;
import com.uinnova.product.eam.comm.model.es.PlanProcessRelationInfo;
import com.uinnova.product.eam.feign.workable.FlowableFeign;
import com.uinnova.product.eam.feign.workable.entity.TaskResponse;
import com.uinnova.product.eam.model.cj.domain.*;
import com.uinnova.product.eam.model.cj.enums.PlanShareEnum;
import com.uinnova.product.eam.model.cj.request.ChapterContextRequest;
import com.uinnova.product.eam.model.cj.request.DeleteModulesRequest;
import com.uinnova.product.eam.model.cj.request.UpdateVersionRequest;
import com.uinnova.product.eam.model.cj.vo.*;
import com.uinnova.product.eam.model.constants.Constants;
import com.uinnova.product.eam.model.constants.FlowableConstant;
import com.uinnova.product.eam.service.asset.BmConfigSvc;
import com.uinnova.product.eam.service.cj.dao.*;
import com.uinnova.product.eam.service.cj.service.*;
import com.uinnova.product.eam.service.impl.IamsCIDesignSvc;
import com.uinnova.product.eam.service.utils.XssCleanerUtil;
import com.uinnova.product.vmdb.comm.model.ci.CCcCi;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiInfo;
import com.uinnova.product.vmdb.provider.ci.bean.CiGroupPage;
import com.uinnova.project.base.diagram.comm.model.ESDiagram;
import com.uinnova.project.service.eam.ESDiagramSvc;
import com.uino.bean.cmdb.base.ESCIAttrDefInfo;
import com.uino.bean.cmdb.base.ESCIClassInfo;
import com.uino.bean.cmdb.query.ESCISearchBean;
import com.uino.bean.permission.base.SysUser;
import com.uino.dao.permission.ESUserSvc;
import com.uino.dao.util.ESUtil;
import com.uino.service.cmdb.microservice.ICIClassSvc;
import com.uino.util.cache.ICacheService;
import com.uino.util.sys.SysUtil;
import lombok.extern.slf4j.Slf4j;
import net.dreamlu.mica.xss.core.XssType;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 方案章节上下文service接口实现
 *
 * @author zhaoxin
 */
@Service
@Slf4j
public class ChapterContextServiceImpl implements ChapterContextService {

    @Value("${http.resource.space}")
    private String httpResouceUrl;

    @Value("${obs.use}")
    private boolean obsUseFlag;

    @Resource
    private ChapterContextDao chapterContextDao;

    @Resource
    private PlanChapterInstanceDao planChapterInstanceDao;

    @Resource
    private PlanChapterInstanceService planChapterInstanceService;

    @Resource
    private PlanDesignInstanceDao planDesignInstanceDao;

    @Resource
    private PlanModuleAnnotationService planModuleAnnotationService;

    @Resource
    @Lazy
    private PlanDesignInstanceService planDesignInstanceService;

    @Resource
    private PlanArtifactService planArtifactService;

    @Resource
    private PlanTemplateChapterDao planTemplateChapterDao;

    @Resource
    private PlanTemplateChapterService templateChapterService;

    @Resource
    private ICacheService iCacheService;

    @Resource
    private PlanArtifactDao planArtifactDao;

    @Resource
    private ESDiagramSvc esDiagramSvc;

    @Resource
    private ICIClassSvc iciClassSvc;

    @Resource
    private IamsCIDesignSvc iamsCiDesignSvc;

    @Resource
    private ESUserSvc esUserSvc;

    @Value("${http.resource.space}")
    private String httpPath;

    @Resource
    private ShareService shareService;

    @Autowired
    private DeliverableTemplateService deliverableTemplateService;

    @Autowired
    private BmConfigSvc bmConfigSvc;

    @Autowired
    private ArchReviewDao archReviewDao;

    @Resource
    private FlowableFeign flowableFeign;

    @Resource
    private PlanProcessRelationInfoDao planProcessRelationInfoDao;

    @Resource
    private PlanTemplateChapterDataDao planTemplateChapterDataDao;

    @Resource
    private DeliverableTemplateDao deliverableTemplateDao;


    /**
     * 保存
     *
     * @param request {@link ChapterContextRequest}
     * @return contextId
     */
    @Override
    public Long save(ChapterContextRequest request) {
        PlanDesignInstanceVO plan = planDesignInstanceService.getById(request.getPlanId());
        if (plan == null) {
            throw new BusinessException("获取方案错误!");
        }
        if (plan.isProcessApproval() && !plan.isEdit()) {
            return -1L;
        }
        SysUser sysUser = SysUtil.getCurrentUserInfo();
        if (!Objects.equals(sysUser.getLoginCode(), plan.getCreatorCode())) {
            PlanDesignShareRecord planDesignShareRecord = new PlanDesignShareRecord();
            planDesignShareRecord.setPlanDesignId(plan.getId());
            planDesignShareRecord.setSharedLoginCode(sysUser.getLoginCode());
            planDesignShareRecord.setStatus(PlanShareEnum.SHARING.getStatus());
            List<PlanDesignShareRecord> shareRecordList = shareService.findPlanShareRecordList(planDesignShareRecord);
            if (!CollectionUtils.isEmpty(shareRecordList)) {
                PlanDesignShareRecord shareRecord = shareRecordList.get(0);
                if (!Objects.equals(shareRecord.getPermission(), 1)
                        && !Objects.equals(shareRecord.getPermission(), 2)
                        && !Objects.equals(shareRecord.getPermission(), 4)) {
                    throw new BusinessException("暂无权限操作方案!");
                }
            } else {
                return -2L;
            }
        }

        ChapterContext context = new ChapterContext();

        BeanUtils.copyProperties(request, context);

        List<ContextModuleVO> moduleVOList = request.getModuleList();
        // 获取保存章节信息中的表格数据，若表格列宽与模板信息不一致，修改更新时间
        changeModifyTime(moduleVOList, request.getId());

        List<PlanArtifact> planArtifactList = new ArrayList<>();

        if (BinaryUtils.isEmpty(moduleVOList)) {
            context.setModuleList(new LinkedList<>());
        } else {

            // 处理附件信息
            moduleVOList.forEach(module -> {
                // 处理附件的地址，去掉host的信息，只保存附件上传的相对路径
                PlanTemplateChapterData moduleDefinition = module.getModuleDefinition();
                if (moduleDefinition != null && Objects.equals(moduleDefinition.getType(), 5)) {
                    Map<String, Object> data = module.getData();
                    Object attachementDataObject = data.get("data");
                    List<Map<String,String>> attachementData = null;
                    if(attachementDataObject != null && attachementDataObject instanceof ArrayList){
                        attachementData = (List<Map<String,String>>)attachementDataObject;
                    }
                    if (attachementData!=null && attachementData.size()>0){
                        attachementData.stream().forEach(attachement->{
                            String respath = attachement.get("resourcePath");
                            if(respath.startsWith(httpPath)){
                                respath = respath.replace(httpPath,"");
                            }
                            attachement.put("resourcePath", respath);
                        });
                    }
                }
            });

            List<ContextModule> moduleList = new ArrayList<>();
            for (int i = 0; i < moduleVOList.size(); i++) {
                ContextModuleVO vo = moduleVOList.get(i);
                Boolean isFromTemplate = vo.getIsFromTemplate();
                if (!isFromTemplate) {
                    Long id = vo.getId();
                    if (id == null || id <= 0) {
                        vo.setId(ESUtil.getUUID());
                    }
                }

                ContextModule contextModule = new ContextModule();
                BeanUtils.copyProperties(vo, contextModule);
                // 配置顺序
                PlanTemplateChapterData moduleDefinition = contextModule.getModuleDefinition();
                moduleDefinition.setConfigOrder(i);
                contextModule.setModuleDefinition(moduleDefinition);
                //对富文本的xss进行过滤
                String data = JSON.toJSONString(vo.getData());
                if(Objects.equals(moduleDefinition.getType(), 1)){
                    if(vo.getData().containsKey("data")){
                        String text = String.valueOf(vo.getData().get("data"));
                        if(null != text) {
                            log.debug("处理xss: " + text);
                            XssCleanerUtil xssCleaner = new XssCleanerUtil();
                            String cleanedText = xssCleaner.clean("", text, XssType.JACKSON);
                            log.debug("处理xss结果: " + cleanedText);
                            vo.getData().put("data", cleanedText);
                            data = JSON.toJSONString(vo.getData());
                        }
                    }
                }
                contextModule.setData(data);
                moduleList.add(contextModule);
            }
            context.setModuleList(moduleList);

            // 保存方案关联制品信息
            moduleVOList.forEach(module -> {
                PlanTemplateChapterData moduleDefinition = module.getModuleDefinition();
                if (moduleDefinition != null && Objects.equals(moduleDefinition.getType(), 1)) {
                    Map<String, Object> data = module.getData();
                    if (data.get("diagramId") != null && !StringUtils.isEmpty(String.valueOf(data.get("diagramId")))) {
                        PlanArtifact planArtifact = new PlanArtifact();
                        planArtifact.setPlanId(request.getPlanId());
                        planArtifact.setChapterId(request.getId());
                        planArtifact.setModuleId(module.getId());
                        planArtifact.setDiagramId(String.valueOf(data.get("diagramId")));
                        List<PlanArtifact> artifactList = planArtifactService.findPlanArtifactList(planArtifact);
                        if (!CollectionUtils.isEmpty(artifactList)) {
                            PlanArtifact artifact = artifactList.get(0);
                            planArtifact.setReleaseDiagramId(artifact.getReleaseDiagramId());
                            planArtifact.setVersion(artifact.getVersion());
                        } else {
                            ESDiagram diagram = null;
                            Long diagramId = esDiagramSvc.queryDiagramInfoByEnergy(String.valueOf(data.get("diagramId")));
                            if (diagramId != null) {
                                diagram = esDiagramSvc.querySimpleDiagramInfoById(diagramId);
                                if (diagram != null) {
                                    // 缩略图
                                    String icon1 = diagram.getIcon1();
                                    if (icon1 != null && !icon1.startsWith(httpResouceUrl)) {
                                        icon1 = httpResouceUrl + icon1;
                                        diagram.setIcon1(icon1);
                                    }
                                }
                            }
                            if (diagram != null && Objects.equals(diagram.getIsOpen(), 1)) {
                                planArtifact.setReleaseDiagramId(diagram.getDEnergy());
                                planArtifact.setVersion(diagram.getReleaseVersion());
                            }
                        }
                        planArtifact.setDiagramProductType(moduleDefinition.getDiagramProductType());
                        planArtifact.setStatus(1);
                        planArtifactList.add(planArtifact);
                    } else if (!StringUtils.isEmpty(moduleDefinition.getDiagramProductType())) {
                        PlanArtifact planArtifact = new PlanArtifact();
                        planArtifact.setPlanId(request.getPlanId());
                        planArtifact.setChapterId(request.getId());
                        planArtifact.setModuleId(module.getId());
                        planArtifact.setDiagramProductType(moduleDefinition.getDiagramProductType());
                        planArtifact.setStatus(1);
                        planArtifactList.add(planArtifact);
                    }
                }
            });
        }

        context.setBusinessId(String.valueOf(ESUtil.getUUID()));
        context.setVersion(String.valueOf(ESUtil.getUUID()));
        context.setStatus(Constants.DRAFT);
        chapterContextDao.saveOrUpdate(context);

        ChapterInstance chapter = planChapterInstanceDao.getById(request.getId());

        SysUser userInfo = SysUtil.getCurrentUserInfo();
        chapter.setModifierCode(userInfo.getLoginCode());
        chapter.setModifierName(userInfo.getUserName());
        chapter.setModifyTime(ESUtil.getNumberDateTime());
        if (!chapter.getName().equals(request.getName())) {
            chapter.setModifyNameType(Constants.CHAPTER_NAME_UPDATE_BY_USER);
        }
        chapter.setName(request.getName());
        if (null != request.getIntroducePlanId()) {
            chapter.setIntroducePlanId(request.getIntroducePlanId());
        }
        if (null != request.getIntroduceChapterId()) {
            chapter.setIntroduceChapterId( request.getIntroduceChapterId());
        }
        if (null != request.getIntroduceChapterName()) {
            chapter.setIntroduceChapterName(request.getIntroduceChapterName());
        }
        if (null != request.getIntroduceWay()) {
            chapter.setIntroduceWay(request.getIntroduceWay());
        }

        chapter.setBusinessId(String.valueOf(ESUtil.getUUID()));
        chapter.setVersion(String.valueOf(ESUtil.getUUID()));
        chapter.setStatus(Constants.DRAFT);

        chapter.setBusinessId(String.valueOf(ESUtil.getUUID()));
        chapter.setVersion(String.valueOf(ESUtil.getUUID()));
        chapter.setStatus(Constants.DRAFT);
        planChapterInstanceDao.saveOrUpdate(chapter);
        planDesignInstanceService.updateModifyTime(request.getPlanId());

        // 新增方案关联制品
        PlanArtifact planArtifact = new PlanArtifact();
        planArtifact.setPlanId(request.getPlanId());
        planArtifact.setChapterId(request.getId());
        planArtifactService.removePlanArtifact(planArtifact);
        if (!CollectionUtils.isEmpty(planArtifactList)) {
            planArtifactService.savePlanArtifact(planArtifactList);
        }
        return request.getId();
    }

    /**
     * 根据id查询
     *
     * @param chapterId 章节id
     */
    @Override
    public ChapterContextVO findById(Long chapterId) {
        ChapterInstance chapter = planChapterInstanceDao.getById(chapterId);
        ChapterContext context = chapterContextDao.getById(chapterId);
        PlanDesignInstance planDesignInstance = planDesignInstanceDao.getById(chapter.getPlanId());
        String chapterSerialNum = planChapterInstanceService.getChapterSerialNum(chapter.getPlanId(), chapterId);
        // 参考规范信息
        ReferencesInfo referencesInfo = new ReferencesInfo();
        if (!BinaryUtils.isEmpty(chapter.getTemplateId())) {
            PlanTemplateChapter planTemplateChapter = planTemplateChapterDao.getById(chapter.getTemplateId());
            if (!BinaryUtils.isEmpty(planTemplateChapter.getReferencesInfo())) {
                referencesInfo = planTemplateChapter.getReferencesInfo();
            }
            // 更新模板表格列宽
            this.updateTableColumnWidthValue(context);
        }

        // 章节里批注列表
        List<PlanModuleAnnotationEntity> annList = annList(planDesignInstance, chapterId, null);

        // key是模块id, value是对应的批注数量
        Map<Long, Long> moduleAnnCountMap =
                annList.stream().collect(Collectors.groupingBy(PlanModuleAnnotationEntity::getPlanChapterModuleId,
                        Collectors.counting()));

        List<ContextModule> moduleList = context.getModuleList();
        Map<Long, Map<String, String>> tableAssetMap = new HashMap<>();
        List<ContextModuleVO> contextModuleVOList = moduleList.stream()
                .sorted(Comparator.comparing(e -> {
                    if (e.getModuleDefinition() != null && e.getModuleDefinition().getConfigOrder() != null) {
                        return e.getModuleDefinition().getConfigOrder();
                    }
                    return 1;
                }))
                .map(module -> {
                    Map<String, Object> data = JSON.parseObject(module.getData(), new TypeReference<Map<String, Object>>() {});

                    if (Objects.equals(2, module.getModuleDefinition().getType())) {
                        handleTableAssets(planDesignInstance, module, tableAssetMap);
                    }
                    module.setData(JSON.toJSONString(data));

                    ContextModuleVO vo = new ContextModuleVO();
                    BeanUtils.copyProperties(module, vo);
                    vo.setData(data);

                    Long count = moduleAnnCountMap.get(vo.getId());
                    if (count == null) {
                        count = 0L;
                    }
                    vo.setAnnotationCount(count.intValue());
                    return vo;
                }).collect(Collectors.toList());

        //对含有自动回显的视图进行保存
        chapterContextDao.saveOrUpdate(context);

        List<ChapterResource> chapterResources = chapter.getChapterResources();
        if (!CollectionUtils.isEmpty(chapterResources)) {
            for (ChapterResource chapterResource : chapterResources) {
                ipStringReplacement(chapterResource);
            }
        }
        // 处理章节附件的地址 返回给前台的附件地址为完整的路径，拼接http.resource.space配置的值
        for (ContextModuleVO contextModule : contextModuleVOList) {
            if (Objects.equals(5, contextModule.getModuleDefinition().getType())) {
                Map<String, Object> dataMap = contextModule.getData();
                if (dataMap != null && dataMap.containsKey(Constants.DATA_SIGN)
                        && !StringUtils.isEmpty(String.valueOf(dataMap.get(Constants.DATA_SIGN)))) {
                    JSONArray jsonArray = JSONArray.parseArray(String.valueOf(dataMap.get(Constants.DATA_SIGN)));
                    JSONArray newJsonArray = new JSONArray();
                    for (int i = 0; i < jsonArray.size(); i++) {
                        JSONObject dataObjJson = JSONObject.parseObject(jsonArray.get(i).toString());
                        if (dataObjJson != null && dataObjJson.containsKey("resourcePath")) {
                            String resourcePath = dataObjJson.getString("resourcePath");
                            if (resourcePath.startsWith("/rsm") || resourcePath.startsWith("rsm")) {
                                resourcePath = resourcePath.replace("/rsm", "").replace("rsm", "");
                            }
                            dataObjJson.put("resourcePath", httpPath + resourcePath);
                        }
                        newJsonArray.add(dataObjJson);
                    }
                    dataMap.put(Constants.DATA_SIGN, newJsonArray);
                }

            }
        }

        ChapterContextVO vo = ChapterContextVO.builder()
                .planId(context.getPlanId())
                .chapterId(context.getId())
                .required(chapter.getRequired())
                .isFromTemplate(chapter.getIsFromTemplate())
                .parentId(context.getPlanId())
                .name(chapter.getName())
                .chapterDesc(context.getChapterDesc())
                .remark(context.getRemark())
                .userAddContent(context.getUserAddContent())
                .moduleList(contextModuleVOList)
                .planName(planDesignInstance.getName())
                .createTime(planDesignInstance.getCreateTime())
                .chapterFullName(chapterSerialNum)
                .tableAssetMap(tableAssetMap)
                .chapterResources(chapter.getChapterResources())
                .planTemplateIntroduceChapterVoList(chapter.getPlanTemplateIntroduceChapterVoList())
                .introducePlanId(chapter.getIntroducePlanId())
                .introduceChapterId(chapter.getIntroduceChapterId())
                .introduceChapterName(chapter.getIntroduceChapterName())
                .introduceWay(chapter.getIntroduceWay())
                .referencesInfo(referencesInfo)
                .build();


        // 判断章节是否已加锁
        String key = Constants.LOCK_CHAPTER_SET + vo.getPlanId() + Constants.COLON + vo.getChapterId() + Constants.COLON;
        String value = (String) iCacheService.getCache(key);
        if (!StringUtils.isEmpty(value)) {
            SysUser sysUser = SysUtil.getCurrentUserInfo();
            if (Objects.equals(value, sysUser.getLoginCode())) {
                vo.setLock(0);
            } else {
                vo.setLock(1);
            }
        } else {
            vo.setLock(0);
        }
        setPointProperties(vo);
        return vo;
    }

    private List<PlanModuleAnnotationEntity> annList(PlanDesignInstance plan, Long chapterId, String processInstanceId) {
        //模板类型是否是"架构方案"
        String configJson = bmConfigSvc.getConfigType("AXEA_CONFIG");
        if (StringUtils.isBlank(configJson)) {
            throw new BinaryException("未查询到国投配置，请联系管理员");
        }
        JSONObject conf = JSON.parseObject(configJson);
        TemplateType templateType = getArchReviewTemplateType(conf);

        TaskResponse taskInfo = null;
        if (BinaryUtils.isEmpty(processInstanceId)) {
            if (templateType.getId().equals(plan.getTypeId())) {
                ArchReview archReview = queryArchReviewBizKey(plan.getId());
                if (!BinaryUtils.isEmpty(archReview)) {
                    taskInfo = flowableFeign.getCurrentTaskDefinitionInfo(archReview.getId().toString(), FlowableConstant.GT_TECHNICAL_SCHEME_APPROVE);
                    if (BinaryUtils.isEmpty(taskInfo) || BinaryUtils.isEmpty(taskInfo.getProcessInstanceId())) {
                        processInstanceId = archReview.getProcessInstanceId();
                    }
                }
            } else {
                taskInfo = flowableFeign.getCurrentTaskDefinitionInfo(String.valueOf(plan.getId()), FlowableConstant.PLAN_DEFINITION_KEY1);
            }

            if (taskInfo != null && !StringUtils.isBlank(taskInfo.getProcessInstanceId())) {
                processInstanceId  = taskInfo.getProcessInstanceId();
            }
        }

        //如果是架构资产中的方案id，同样查不到评审信息，根据发布方案id查询对应的版本（uino_cj_plan_process_relation存储了流程与方案版本的关系）
        if (BinaryUtils.isEmpty(processInstanceId)) {
            PlanProcessRelationInfo planProcessRelationInfo = getByPlanId(plan.getId());
            if (!BinaryUtils.isEmpty(planProcessRelationInfo)) {
                processInstanceId  = planProcessRelationInfo.getProcessInstanceId();
            } else {
                return new ArrayList<>();
            }
        }
        BoolQueryBuilder query = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("delFlag", false))
                .must(QueryBuilders.termQuery("planId", plan.getId()))
                .must(QueryBuilders.termQuery("taskDefinitionKey.keyword", processInstanceId));
        if (chapterId != null) {
            query.must(QueryBuilders.termQuery("planChapterId", chapterId));
        }
        FieldSortBuilder sortBuilder = new FieldSortBuilder("createTime").order(SortOrder.DESC);
        return planModuleAnnotationService.getSortListByQuery(1, 3000, query,
                ListUtil.of(sortBuilder)).getData();
    }

    /**
     * 根据方案id查询对应版本流程关联关系
     * @param planId
     * @return
     */
    private PlanProcessRelationInfo getByPlanId(Long planId) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery()
                .must(QueryBuilders.termQuery("planId", planId));
        List<PlanProcessRelationInfo> list = planProcessRelationInfoDao.selectListByQuery(1, 1, queryBuilder);
        if (BinaryUtils.isEmpty(list)) {
            return null;
        }
        return list.get(0);
    }
    private ArchReview queryArchReviewBizKey(Long planId) {
        TermQueryBuilder query = QueryBuilders.termQuery("planIds", planId);
        Page<ArchReview> page = archReviewDao.getSortListByQuery(1,1, query,"createTime", false);
        return CollectionUtils.isEmpty(page.getData()) ? null : page.getData().get(0);
    }

    private TemplateType getArchReviewTemplateType(JSONObject conf) {
        if (conf == null) {
            throw new BinaryException("未查询到国投分类映射配置，请联系管理员");
        }
        String archReviewTemplateTypeName = conf.getString("archReviewTemplateTypeName");
        if (StringUtils.isBlank(archReviewTemplateTypeName)) {
            throw new BinaryException("未查询到国投架构方案模板类型配置，请联系管理员");
        }
        TemplateType templateType = deliverableTemplateService.getTemplateTypeByName(archReviewTemplateTypeName);
        if (templateType == null) {
            log.error("未查询到国投架构方案模板类型配置[archReviewTemplateTypeName:{}]，请联系管理员", archReviewTemplateTypeName);
            throw new BinaryException("未查询到国投架构方案模板类型配置，请联系管理员");
        }
        return templateType;
    }

    private void ipStringReplacement(ChapterResource chapterResource) {
        Pattern pattern = Pattern.compile("(http|https)://([0-9]{1,3}\\.){3}[0-9]{1,3}");
        String resourcePath = chapterResource.getResourcePath();
        Matcher matcher = pattern.matcher(resourcePath);
        String newPath = matcher.replaceAll("");
        if(newPath.startsWith("/rsm") || newPath.startsWith("rsm")){
            newPath = newPath.replace("/rsm","").replace("rsm","");
        }
        chapterResource.setResourcePath(httpPath+newPath);

    }

    /**
     * 封装数据表格资产
     */
    private void handleTableAssets(PlanDesignInstance planDesignInstance, ContextModule module, Map<Long, Map<String, String>> map) {
        PlanTemplateChapterData moduleDefinition = module.getModuleDefinition();
        Long id = module.getId();
        // 系统分类
        Long classId = planDesignInstance.getDefaultSystemClassId();
        if (classId == null) {
            return;
        }
        List<ESCIAttrDefInfo> attrDefList = new ArrayList<>();
        ESCIClassInfo esciClassInfo = iciClassSvc.queryESClassInfoById(classId);
        if (esciClassInfo != null && !CollectionUtils.isEmpty(esciClassInfo.getAttrDefs())) {
            attrDefList = esciClassInfo.getAttrDefs();
        }
        if (!CollectionUtils.isEmpty(attrDefList)) {
            Map<Long, String> attrMap = attrDefList.stream().collect(Collectors.toMap(ESCIAttrDefInfo::getId, ESCIAttrDefInfo::getProName));
            List<RowTableContentVo> dataTableContent = moduleDefinition.getDataTableContent();
            Map<String, String> itemMap = new HashMap<>();
            if (!CollectionUtils.isEmpty(dataTableContent)) {
                dataTableContent.forEach(content -> {
                    if (Objects.equals(10, content.getType()) && !StringUtils.isEmpty(content.getCopyConstraint())) {
                        Long attId = null;
                        String item = content.getCopyConstraint();
                        JSONObject jsonObject = JSONObject.parseObject(item);
                        if (jsonObject != null && !StringUtils.isEmpty(jsonObject.getString("ids"))
                                && attrMap.keySet().contains(Long.valueOf(jsonObject.getString("ids")))) {
                            attId = Long.valueOf(jsonObject.getString("ids"));
                        }
                        if (attId != null) {
                            String preName = attrMap.get(attId);

                            CcCiInfo ci = null;
                            ESCISearchBean bean = new ESCISearchBean();
                            CCcCi cdt = new CCcCi();
                            cdt.setCiCode(planDesignInstance.getDefaultSystemCiCode());
                            bean.setCdt(cdt);
                            CiGroupPage ciGroupPage = iamsCiDesignSvc.queryPageBySearchBean(bean, false);
                            if (ciGroupPage != null && !CollectionUtils.isEmpty(ciGroupPage.getData())) {
                                ci = ciGroupPage.getData().get(0);
                            }

                            if (ci != null) {
                                Map<String, String> attrs = ci.getAttrs();
                                String attr = attrs.get(preName);
                                itemMap.put(content.getName(), attr);
                            } else {
                                itemMap.put(content.getName(), "");
                            }
                        } else {
                            itemMap.put(content.getName(), "");
                        }
                    }
                });
            }
            map.put(id, itemMap);
        }
    }

    /**
     * 模块删除
     *
     * @param request {@link DeleteModulesRequest}
     */
    @Override
    public void delModule(DeleteModulesRequest request) {
        List<Long> moduleIdList = request.getModuleIdList();
        if (BinaryUtils.isEmpty(moduleIdList)) {
            return;
        }

        ChapterContext chapterContext = chapterContextDao.getById(request.getChapterId());
        if (chapterContext == null) {
            throw new BusinessException("章节不存在或已被删除");
        }

        List<ContextModule> moduleList = chapterContext.getModuleList();
        if (BinaryUtils.isEmpty(moduleList)) {
            return;
        }

        int beforeDeleteSize = moduleIdList.size();

        moduleList.removeIf(module -> checkDel(moduleIdList, module));

        int afterDeleteSize = moduleList.size();

        if (afterDeleteSize < beforeDeleteSize) {

            chapterContextDao.saveOrUpdate(chapterContext);

            planDesignInstanceService.updateModifyTime(chapterContext.getPlanId());
        }

    }

    @Override
    public ChapterContext findIntroduceContextById(Long introduceChapterId) {
        return chapterContextDao.getById(introduceChapterId);
    }

    @Override
    public Boolean updateAllContextDiagramVersion(Long planId) {
        List<DiagramVersionBO> diagramVersions = planChapterInstanceService.findDiagramVersions(planId);
        Set<Long> chapterIds = diagramVersions.stream().map(item -> item.getChapterId()).collect(Collectors.toSet());
        List<Long> findChapterId = new ArrayList<>();
        Map<Long, DiagramVersionBO> diagramVersionMap = diagramVersions.stream().collect(Collectors.toMap(DiagramVersionBO :: getModuleId, t2 -> t2, (v1, v2) -> v1));
        Set<Long> moduleSet = diagramVersionMap.keySet();
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termsQuery("moduleList.id",moduleSet));
        queryBuilder.must(QueryBuilders.termQuery("planId",planId));
        List<ChapterContext> chapterContextList = chapterContextDao.getListByQuery(queryBuilder);
        for (ChapterContext chapterContext : chapterContextList) {
            if (CollectionUtils.isEmpty(chapterIds) || !chapterIds.contains(chapterContext.getId())) {
                continue;
            }
            findChapterId.add(chapterContext.getId());
            for (ContextModule contextModule : chapterContext.getModuleList()) {
                if (!moduleSet.contains(contextModule.getId())) {
                    continue;
                }
                Long moduleId = contextModule.getId();
                DiagramVersionBO diagramVersionBO = diagramVersionMap.get(moduleId);
                String data = contextModule.getData();
                JSONObject jsonObjectData = JSONObject.parseObject(data);
                jsonObjectData.put("author",diagramVersionBO.getEamReleaseHistoryDTO().getReleaseUser().getUserName());
                jsonObjectData.put("title",diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getDiagram().getName());
                jsonObjectData.put("diagramId",diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getDEnergy());
                jsonObjectData.put("viewType",diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getDiagram().getViewType());
                jsonObjectData.put("isOpen",diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getDiagram().getIsOpen());
                jsonObjectData.put("dirType",diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getDiagram().getDirType());
                jsonObjectData.put("dirId",diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getDiagram().getDirId());
                jsonObjectData.put("releaseVersion",diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getVersionNo());
                log.info("更滑视图版本为:%d",diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getVersionNo());
                contextModule.setData(jsonObjectData.toJSONString());
            }
        }
        //批量保存更新视图最新版本
        chapterContextDao.saveOrUpdateBatch(chapterContextList);
        //下面处理视图方案关联表  把关联表方案关联的视图更新
        BoolQueryBuilder artifactQueryBuilder = QueryBuilders.boolQuery();
        artifactQueryBuilder.must(QueryBuilders.termsQuery("moduleId",moduleSet));
        artifactQueryBuilder.must(QueryBuilders.termQuery("planId",planId));
        artifactQueryBuilder.must(QueryBuilders.termsQuery("chapterId",findChapterId));
        List<PlanArtifact> planArtifactList = planArtifactDao.getListByQuery(artifactQueryBuilder);
        for (PlanArtifact planArtifact : planArtifactList) {
            DiagramVersionBO diagramVersionBO = diagramVersionMap.get(planArtifact.getModuleId());
            planArtifact.setVersion(diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getVersionNo());
            planArtifact.setReleaseDiagramId(diagramVersionBO.getEamReleaseHistoryDTO().getReleaseInfo().getDEnergy());
        }
        //批量更细关联表
        planArtifactDao.saveOrUpdateBatch(planArtifactList);

        return true;
    }

    @Override
    public Boolean updateSingleDiagramVersion(UpdateVersionRequest updateVersionRequest) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.must(QueryBuilders.termQuery("moduleList.id",updateVersionRequest.getModuleId()));
        queryBuilder.must(QueryBuilders.termQuery("planId",updateVersionRequest.getPlanId()));
        queryBuilder.must(QueryBuilders.termQuery("id",updateVersionRequest.getChapterId()));
        List<ChapterContext> chapterContextList = chapterContextDao.getListByQuery(queryBuilder);
        for (ChapterContext chapterContext : chapterContextList) {
            for (ContextModule contextModule : chapterContext.getModuleList()) {
                if (!contextModule.getId().equals(updateVersionRequest.getModuleId())) {
                    continue;
                }
                String data = contextModule.getData();
                JSONObject jsonObjectData = JSONObject.parseObject(data);
                jsonObjectData.put("author",updateVersionRequest.getAuthor());
                jsonObjectData.put("title",updateVersionRequest.getTitle());
                jsonObjectData.put("diagramId",updateVersionRequest.getDiagramId());
                jsonObjectData.put("viewType",updateVersionRequest.getViewType());
                jsonObjectData.put("isOpen",updateVersionRequest.getIsOpen());
//                jsonObjectData.put("dirType",updateVersionRequest.getDirType());
                jsonObjectData.put("dirId",updateVersionRequest.getDirId());
                jsonObjectData.put("releaseVersion",updateVersionRequest.getReleaseVersion());
                contextModule.setData(jsonObjectData.toJSONString());
            }
        }
        chapterContextDao.saveOrUpdateBatch(chapterContextList);


        BoolQueryBuilder artifactQueryBuilder = QueryBuilders.boolQuery();
        artifactQueryBuilder.must(QueryBuilders.termQuery("moduleId",updateVersionRequest.getModuleId()));
        artifactQueryBuilder.must(QueryBuilders.termQuery("planId",updateVersionRequest.getPlanId()));
        artifactQueryBuilder.must(QueryBuilders.termQuery("chapterId",updateVersionRequest.getChapterId()));
        List<PlanArtifact> planArtifactList = planArtifactDao.getListByQuery(artifactQueryBuilder);
        PlanArtifact planArtifact = planArtifactList.get(0);

        planArtifact.setVersion(updateVersionRequest.getReleaseVersion());
        planArtifact.setReleaseDiagramId(updateVersionRequest.getDiagramId());

        //批量更细关联表
        planArtifactDao.saveOrUpdate(planArtifact);
        return true;
    }

    private boolean checkDel(List<Long> moduleIdList, ContextModule module) {
        boolean containsDelId = moduleIdList.contains(module.getId());
        if (!containsDelId) {
            return false;
        }

        PlanTemplateChapterData definition = module.getModuleDefinition();
        if (definition == null) {
            return true;
        }

        Integer type = definition.getType();
        if (type == null) {
            return true;
        }

        // 1:制品 2:表格 3:富文本
        int diagram = 1;
        int table = 2;
        int richText = 3;

        String requiredFlag;
        if (type == diagram) {
            requiredFlag = definition.getProductRequired();
        } else if (type == table) {
            requiredFlag = definition.getDataTableRequired();
        } else if (type == richText) {
            requiredFlag = definition.getRichTextRequired();
        } else {
            return true;
        }

        // 1必填 0非必填
        String required = "1";
        return !StringUtils.equals(required, requiredFlag);
    }

    /**
     * 设置下一个章节和上一个章节的参数
     */
    private void setPointProperties(ChapterContextVO vo) {
        ChapterInstance currentChapter = planChapterInstanceDao.getById(vo.getChapterId());
        /*Double currentChapterOrderId = currentChapter.getOrderId();

        TermQueryBuilder parentId = QueryBuilders.termQuery("parentId", currentChapter.getParentId());
        TermQueryBuilder planId = QueryBuilders.termQuery("planId", currentChapter.getPlanId());
        TermQueryBuilder deleted = QueryBuilders.termQuery("deleted", false);
        RangeQueryBuilder orderIdGt = QueryBuilders.rangeQuery("orderId").gt(currentChapterOrderId);
        RangeQueryBuilder orderIdLt = QueryBuilders.rangeQuery("orderId").lt(currentChapterOrderId);

        BoolQueryBuilder nextQueryBuilder = QueryBuilders.boolQuery()
                .must(parentId)
                .must(planId)
                .must(deleted)
                .must(orderIdGt);

        BoolQueryBuilder preQueryBuilder = QueryBuilders.boolQuery()
                .must(parentId)
                .must(planId)
                .must(deleted)
                .must(orderIdLt);

        List<ChapterInstance> nextChapterList = planChapterInstanceDao.getSortListByQuery(1, 1,
                nextQueryBuilder, "orderId", true).getData();

        List<ChapterInstance> preChapterList = planChapterInstanceDao.getSortListByQuery(1, 1,
                preQueryBuilder, "orderId", false).getData();*/

        List<ChapterInstance> chapterList = new ArrayList<>();
        List<PlanChapterVO> chapterVOList = planChapterInstanceService.getChapterList(currentChapter.getPlanId());
        if (!CollectionUtils.isEmpty(chapterVOList)) {
            chapterVOList.forEach(chapterVO -> {
                ChapterInstance chapter = new ChapterInstance();
                BeanUtils.copyProperties(chapterVO, chapter);
                chapterList.add(chapter);
                if (!CollectionUtils.isEmpty(chapterVO.getChildChapterList())) {
                    handleChildChapter(chapterVO.getChildChapterList(), chapterList);
                }
            });
        }

        int index = 0;
        for (int i = 0; i < chapterList.size(); i++) {
            if (vo.getChapterId().equals(chapterList.get(i).getId())) {
                index = i;
                break;
            }
        }

        boolean hasNext = index < chapterList.size()-1;
        boolean hasPrevious = index > 0;

        vo.setHasNext(hasNext);
        vo.setHasPrevious(hasPrevious);
        vo.setPreviousId(!hasPrevious ? -1 : chapterList.get(index - 1).getId());
        vo.setNextId(!hasNext ? -1 : chapterList.get(index + 1).getId());
    }

    private void handleChildChapter(List<PlanChapterVO> childChapterList, List<ChapterInstance> chapterList) {
        if (!CollectionUtils.isEmpty(childChapterList)) {
            childChapterList.forEach(chapterVO -> {
                ChapterInstance chapter = new ChapterInstance();
                BeanUtils.copyProperties(chapterVO, chapter);
                chapterList.add(chapter);
                if (!CollectionUtils.isEmpty(chapterVO.getChildChapterList())) {
                    handleChildChapter(chapterVO.getChildChapterList(), chapterList);
                }
            });
        }
    }

    @Override
    public List<ChapterContextVO> findByPlanId(Long planId, String processInstanceId) {
        PlanDesignInstance plan = planDesignInstanceDao.getById(planId);
        BoolQueryBuilder query = QueryBuilders.boolQuery();
        query.must(QueryBuilders.termQuery("planId",planId));
        List<ChapterContext> contextList = chapterContextDao.getListByQuery(query);
        List<ChapterInstance> chapterList = planChapterInstanceService.getChapterByPlanId(planId);
        Map<Long, ChapterInstance> chapterMap = chapterList.stream().collect(Collectors.toMap(ChapterInstance::getId, e -> e, (k1, k2) -> k2));

        List<PlanTemplateChapter> templateChapterList = templateChapterService.findPlanChapterList(plan.getTemplateId());
        Map<Long, PlanTemplateChapter> templateMap = templateChapterList.stream().collect(Collectors.toMap(PlanTemplateChapter::getPlanTemplateId, e -> e, (k1, k2) -> k2));
        // 章节里批注列表
        List<PlanModuleAnnotationEntity> annList = annList(plan, null, processInstanceId);
        Map<Long, List<PlanModuleAnnotationEntity>> annGroup = annList.stream().collect(Collectors.groupingBy(PlanModuleAnnotationEntity::getPlanChapterModuleId));

        //获取上下章节信息
        Map<Long, ChapterContextVO> chapterPointMap = getChapterPointMap(chapterList);

        List<ChapterContextVO> result = new ArrayList<>();

        for (ChapterContext context : contextList) {
            List<ContextModule> moduleList = context.getModuleList();
            Map<Long, Map<String, String>> tableAssetMap = new HashMap<>();
            List<ContextModuleVO> contextModuleVOList = new ArrayList<>();
            this.updateTableColumnWidthValue(context);
            for (ContextModule module : moduleList) {
                Map<String, Object> data = JSON.parseObject(module.getData(), new TypeReference<Map<String, Object>>() {});

                if (Objects.equals(2, module.getModuleDefinition().getType())) {
                    handleTableAssets(plan, module, tableAssetMap);
                }
                module.setData(JSON.toJSONString(data));

                ContextModuleVO vo = EamUtil.copy(module, ContextModuleVO.class);
                vo.setData(data);

                List<PlanModuleAnnotationEntity> contextAnn = annGroup.getOrDefault(vo.getId(), Collections.emptyList());
                vo.setAnnotationCount(contextAnn.size());
                contextModuleVOList.add(vo);
                if(!Objects.equals(5, vo.getModuleDefinition().getType()) || CollectionUtils.isEmpty(vo.getData())){
                    continue;
                }
                Object dataSign = vo.getData().get(Constants.DATA_SIGN);
                if (BinaryUtils.isEmpty(dataSign)) {
                    continue;
                }
                List<JSONObject> jsonObjects = JSON.parseArray(dataSign.toString(), JSONObject.class);
                for (JSONObject each : jsonObjects) {
                    if (each != null && each.containsKey("resourcePath")) {
                        String resourcePath = each.getString("resourcePath");
                        if (resourcePath.startsWith("/rsm") || resourcePath.startsWith("rsm")) {
                            resourcePath = resourcePath.replace("/rsm", "").replace("rsm", "");
                        }
                        each.put("resourcePath", httpPath + resourcePath);
                    }
                }
                vo.getData().put(Constants.DATA_SIGN, JSON.toJSONString(jsonObjects));
            }
            contextModuleVOList.sort(Comparator.comparing(e -> {
                if (e.getModuleDefinition() != null && e.getModuleDefinition().getConfigOrder() != null) {
                    return e.getModuleDefinition().getConfigOrder();
                }
                return 1;
            }));
            ChapterInstance chapter = chapterMap.get(context.getId());
            if(chapter == null){
                continue;
            }
            if (!CollectionUtils.isEmpty(chapter.getChapterResources())) {
                chapter.getChapterResources().forEach(this::ipStringReplacement);
            }
            // 参考规范信息
            ReferencesInfo referencesInfo = new ReferencesInfo();
            if (!BinaryUtils.isEmpty(chapter.getTemplateId()) && !BinaryUtils.isEmpty(templateMap.get(chapter.getTemplateId()))) {
                referencesInfo = templateMap.get(chapter.getTemplateId()).getReferencesInfo();
            }
            String chapterSerialNum = String.format("%s %s", chapter.getSerialNum(), chapter.getName());
            // 处理章节附件的地址 返回给前台的附件地址为完整的路径，拼接http.resource.space配置的值
            ChapterContextVO copy = EamUtil.copy(chapter, ChapterContextVO.class);
            copy.setChapterId(chapter.getId());
            copy.setChapterDesc(context.getChapterDesc());
            copy.setRemark(context.getRemark());
            copy.setUserAddContent(context.getUserAddContent());
            copy.setModuleList(contextModuleVOList);
            copy.setPlanName(plan.getName());
            copy.setCreateTime(plan.getCreateTime());
            copy.setChapterFullName(chapterSerialNum);
            copy.setTableAssetMap(tableAssetMap);
            copy.setReferencesInfo(referencesInfo);
            ChapterContextVO point = chapterPointMap.get(chapter.getId());
            copy.setHasPrevious(point.getHasPrevious());
            copy.setPreviousId(point.getPreviousId());
            copy.setHasNext(point.getHasNext());
            copy.setNextId(point.getNextId());
            result.add(copy);
        }
        return result;
    }


    @Override
    public void updateTableColumnWidthValue(ChapterContext planContext) {
        // 参数校验
        if (planContext == null || CollectionUtils.isEmpty(planContext.getModuleList())) {
            log.info("章节上下文为空或不包含模块");
            return;
        }

        // 检查是否包含表格数据
        if (!haveTableData(planContext)) {
            log.info("当前章节不包含表格数据");
            return;
        }

        List<Long> templateChapterDataIds = planContext.getModuleList().stream().map(ContextModule::getId).collect(Collectors.toList());

        // 获取查询章节对应的模板信息
        if (CollectionUtils.isEmpty(templateChapterDataIds)) {
            log.info("当前章节未绑定模板信息");
            return;
        }

        // 获取模板章节数据列表
        List<PlanTemplateChapterData> templateContextList = planTemplateChapterDataDao.getListByQuery(
                QueryBuilders.termsQuery("id", templateChapterDataIds));

        if (CollectionUtils.isEmpty(templateContextList)) {
            log.info("当前章节绑定模板数据信息不存在, templateChapterDataIds={}", JSON.toJSONString(templateChapterDataIds));
            return;
        }
        Long templatePlanId = templateContextList.
                stream().
                map(PlanTemplateChapterData::getPlanTemplateId).
                collect(Collectors.toList()).get(0);

        // 获取模板详情 判断是否停用
        DeliverableTemplate templateInfo = deliverableTemplateDao.getById(templatePlanId);
        if (BinaryUtils.isEmpty(templateInfo)) {
            return;
        }

        Integer status = templateInfo.getStatus();
        if (3 != status) {
            log.info("当前模板未启用, templatePlanId={}", templatePlanId);
            return;
        }

        // 创建模板数据ID到模板数据的映射
        Map<Long, PlanTemplateChapterData> templateContextMap = templateContextList.stream()
                .collect(Collectors.toMap(
                        PlanTemplateChapterData::getId,
                        Function.identity(),
                        (k1, k2) -> k1
                ));

        // 记录更新的模块数量
        List<String> updatedModuleNames = new ArrayList<>();

        // 遍历章节中的所有模块
        for (ContextModule module : planContext.getModuleList()) {
            // 获取模块定义
            PlanTemplateChapterData moduleDefinition = module.getModuleDefinition();

            // 检查模块定义是否有效
            if (moduleDefinition == null || moduleDefinition.getId() == null) {
                continue;
            }

            // 检查是否为表格类型
            Integer contextType = moduleDefinition.getType();
            if (contextType == null || contextType != 2) {
                continue;
            }

            // 获取对应的模板数据
            PlanTemplateChapterData templateData = templateContextMap.get(moduleDefinition.getId());
            if (templateData == null) {
                log.info("模块 {} 对应的模板数据不存在", moduleDefinition.getId());
                continue;
            }

            // 检查修改时间
            Long templateModifyTime = templateData.getModifyTime();
            Long contextModifyTime = moduleDefinition.getModifyTime();

            if (templateModifyTime == null || contextModifyTime == null || templateModifyTime <= contextModifyTime) {
                log.info("模块 {} 的方案更新时间大于等于模板更新时间，不进行列宽更新", moduleDefinition.getId());
                continue;
            }

            // 检查表格是否相等
            if (isEqualTable(templateData, moduleDefinition, moduleDefinition.getDataTableForm())) {
                log.info("模块 {} 的表格定义与模板相同，不需要更新", moduleDefinition.getId());
                continue;
            }

            // 根据表格类型更新列宽信息
            updateTableColumnWidth(moduleDefinition, templateData);
            updatedModuleNames.add(moduleDefinition.getDataTableName());
        }

        if (!CollectionUtils.isEmpty(updatedModuleNames)) {
            log.info("成功更新 {} 个模块的表格列宽:{}", updatedModuleNames.size(), JSON.toJSONString(updatedModuleNames));
        } else {
            log.info("没有需要更新列宽的模块");
        }
    }

    /**
     * 根据表格类型更新列宽信息
     *
     * @param moduleDefinition 模块定义
     * @param templateData 模板数据
     */
    private void updateTableColumnWidth(PlanTemplateChapterData moduleDefinition, PlanTemplateChapterData templateData) {
        if (moduleDefinition == null || templateData == null) {
            return;
        }

        Integer tableForm = moduleDefinition.getDataTableForm();
        if (tableForm == null) {
            return;
        }

        switch (tableForm) {
            case 1: // 横向表格处理
                moduleDefinition.setDataTableContent(templateData.getDataTableContent());
                log.info("更新横向表格列宽信息, 模块ID={}", moduleDefinition.getId());
                break;

            case 2: // 纵向表格处理
                moduleDefinition.setFirstColumnWidth(templateData.getFirstColumnWidth());
                moduleDefinition.setFirstColumnWidthValue(templateData.getFirstColumnWidthValue());
                log.info("更新纵向表格列宽信息, 模块ID={}, 首列宽={}, 首列宽值={}",
                        moduleDefinition.getId(), templateData.getFirstColumnWidth(), templateData.getFirstColumnWidthValue());
                break;

            case 3: // 矩阵表格处理
                moduleDefinition.setFirstColumnWidth(templateData.getFirstColumnWidth());
                moduleDefinition.setFirstColumnWidthValue(templateData.getFirstColumnWidthValue());
                moduleDefinition.setMatrixRow(templateData.getMatrixRow());
                log.info("更新矩阵表格列宽信息, 模块ID={}, 首列宽={}, 首列宽值={}, 矩阵行数={}",
                        moduleDefinition.getId(), templateData.getFirstColumnWidth(),
                        templateData.getFirstColumnWidthValue(),
                        templateData.getMatrixRow() != null ? templateData.getMatrixRow().size() : 0);
                break;

            default:
                log.info("未知的表格形式: {}, 模块ID={}", tableForm, moduleDefinition.getId());
        }

        // 更新修改时间
        moduleDefinition.setModifyTime(templateData.getModifyTime());
    }

    /**
     * 判断两个表格定义是否相等
     *
     * @param temp 模板表格定义
     * @param data 数据表格定义
     * @param tableForm 表格形式（1:横向表格, 2:纵向表格, 3:矩阵表格）
     * @return 如果两个表格定义相等返回true，否则返回false
     */
    private Boolean isEqualTable(PlanTemplateChapterData temp, PlanTemplateChapterData data, Integer tableForm) {
        // 参数校验
        if (temp == null || data == null || tableForm == null) {
            log.info("表格比较参数为空");
            return Boolean.FALSE;
        }

        // 如果两个对象是同一个引用，直接返回true
        if (temp == data) {
            return Boolean.TRUE;
        }

        // 根据表格形式进行不同的比较
        switch (tableForm) {
            case 1: // 横向表格处理
                return isEqualHorizontalTable(temp, data);

            case 2: // 纵向表格处理
                return isEqualVerticalTable(temp, data);

            case 3: // 矩阵表格处理
                return isEqualMatrixTable(temp, data);

            default:
                log.error("未知的表格形式: {}", tableForm);
                return Boolean.FALSE;
        }
    }

    /**
     * 判断两个横向表格定义是否相等
     */
    private Boolean isEqualHorizontalTable(PlanTemplateChapterData temp, PlanTemplateChapterData data) {
        return compareTable(temp, data, Boolean.FALSE);
    }

    /**
     * 表格对比
     *
     * @param temp 模板表格定义
     * @param data 数据表格定义
     * @param checkFirstCol 是否校验首列宽度（true: 矩阵表格列, false: 普通表格）
     * @return 如果表格内容相同返回TRUE，否则返回FALSE
     */
    private Boolean compareTable(PlanTemplateChapterData temp, PlanTemplateChapterData data, Boolean checkFirstCol) {
        // 参数校验
        if (temp == null || data == null) {
            log.info("表格比较参数为空");
            return Boolean.FALSE;
        }

        // 根据表格类型获取对应的内容列表
        List<RowTableContentVo> tempTableContent = checkFirstCol ? temp.getMatrixRow() : temp.getDataTableContent();
        List<RowTableContentVo> dataTableContent = checkFirstCol ? data.getMatrixRow() : data.getDataTableContent();

        // 检查列表是否为空
        boolean isTempEmpty = (tempTableContent == null || tempTableContent.isEmpty());
        boolean isDataEmpty = (dataTableContent == null || dataTableContent.isEmpty());

        // 如果两个列表都为空，返回true
        if (isTempEmpty && isDataEmpty) {
            return Boolean.TRUE;
        }

        // 如果只有一个列表为空，返回false
        if (isTempEmpty || isDataEmpty) {
            log.info("模板或数据表格内容为空");
            return Boolean.FALSE;
        }

        // 检查首列宽度
        boolean firstColumnWidthEqual = isEqualFirstColumnWidthAndValue(temp.getFirstColumnWidth(), data.getFirstColumnWidth());
        boolean firstColumnWidthValueEqual = isEqualFirstColumnWidthAndValue(temp.getFirstColumnWidthValue(), data.getFirstColumnWidthValue());

        // 检查列数是否相同
        if (tempTableContent.size() != dataTableContent.size()) {
            log.info("普通表格列数不一致: 模板={}, 方案={}",
                    tempTableContent.size(), dataTableContent.size());
            return Boolean.TRUE;
        }

        // 比较列名是否相同
        Map<String, RowTableContentVo> tempMap = createColumnMap(tempTableContent);
        Map<String, RowTableContentVo> dataMap = createColumnMap(dataTableContent);

        // 列名不一致不更新
        if (!tempMap.keySet().equals(dataMap.keySet())) {
            log.info("模板列名与方案内列名不一致");
            return Boolean.TRUE;
        }

        // 比较列宽是否相同
        for (String columnKey : tempMap.keySet()) {
            RowTableContentVo tempColumn = tempMap.get(columnKey);
            RowTableContentVo dataColumn = dataMap.get(columnKey);

            if (!isEqualColumnWidthValue(tempColumn, dataColumn)) {
                // 提取列名（去除可能的类ID后缀）
                String columnName = columnKey.contains("-") ?
                        columnKey.substring(0, columnKey.indexOf("-")) : columnKey;
                log.info("列 '{}' 的宽度不一致", columnName);
                return Boolean.FALSE;
            }
        }

        if (!firstColumnWidthEqual || !firstColumnWidthValueEqual) {
            log.info("模板列宽与方案内列宽不一致: 模板首列宽={}, 方案首列宽={}, 模板首列宽值={}, 方案首列宽值={}",
                    temp.getFirstColumnWidth(), data.getFirstColumnWidth(),
                    temp.getFirstColumnWidthValue(), data.getFirstColumnWidthValue());
            return Boolean.FALSE;
        }

        return Boolean.TRUE;
    }

    /**
     * 创建列映射
     *
     * @param columns 列列表
     * @return 列名到列对象的映射
     */
    private Map<String, RowTableContentVo> createColumnMap(List<RowTableContentVo> columns) {
        if (columns == null) {
            return Collections.emptyMap();
        }

        return columns.stream()
                .collect(Collectors.toMap(
                        e -> e.getName() + "-" + (BinaryUtils.isEmpty(e.getClassId()) ? "0" : e.getClassId()),
                        Function.identity(),
                        (k1, k2) -> k1
                ));
    }

    /**
     * 判断两个纵向表格定义是否相等
     */
    private Boolean isEqualVerticalTable(PlanTemplateChapterData temp, PlanTemplateChapterData data) {
        // 比较首列宽度
        if (!isEqualFirstColumnWidthAndValue(temp.getFirstColumnWidth(), data.getFirstColumnWidth()) ||
                !isEqualFirstColumnWidthAndValue(temp.getFirstColumnWidthValue(), data.getFirstColumnWidthValue())) {
            log.info("模板列宽与方案内列宽不一致: 模板首列宽={}, 方案首列宽={}, 模板首列宽值={}, 方案首列宽值={}",
                    temp.getFirstColumnWidth(), data.getFirstColumnWidth(),
                    temp.getFirstColumnWidthValue(), data.getFirstColumnWidthValue());
            return Boolean.FALSE;
        }

        return Boolean.TRUE;
        // 比较表格内容
        // return isEqualColumnInfo(temp.getDataTableContent(), data.getDataTableContent());
    }

    /**
     * 判断两个矩阵表格定义是否相等
     */
    private Boolean isEqualMatrixTable(PlanTemplateChapterData temp, PlanTemplateChapterData data) {
        return compareTable(temp, data, Boolean.TRUE);
    }

    /**
     * 判断两个列的宽度值是否相等
     */
    private Boolean isEqualColumnWidthValue(RowTableContentVo tempColumn, RowTableContentVo dataColumn) {
        if (tempColumn == null && dataColumn == null) {
            return Boolean.TRUE;
        }

        if (tempColumn == null || dataColumn == null) {
            return Boolean.FALSE;
        }

        if (!isEqualFirstColumnWidthAndValue(tempColumn.getColumnWidthValue(), dataColumn.getColumnWidthValue()) ||
                !isEqualFirstColumnWidthAndValue(tempColumn.getColumnWidth(), dataColumn.getColumnWidth())) {
            return Boolean.FALSE;
        }

        return Boolean.TRUE;
    }

    private Boolean haveTableData(ChapterContext oldContext) {
        List<ContextModule> moduleList = oldContext.getModuleList();
        for (ContextModule module : moduleList) {
            if (module.getModuleDefinition().getType() == 2) {
                return Boolean.TRUE;
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 修改时间
     *
     * @param moduleVOList 模块列表
     * @param chapterId 章节ID
     */
    private void changeModifyTime(List<ContextModuleVO> moduleVOList, Long chapterId) {
        // 参数校验
        if (CollectionUtils.isEmpty(moduleVOList) || chapterId == null) {
            return;
        }

        // 筛选出表格类型的模块
        List<ContextModuleVO> tableModules = moduleVOList.stream()
                .filter(module -> {
                    PlanTemplateChapterData definition = module.getModuleDefinition();
                    return definition != null
                            && definition.getType() != null
                            && definition.getType() == 2
                            && definition.getId() != null;
                })
                .collect(Collectors.toList());

        if (tableModules.isEmpty()) {
            return;
        }

        // 获取数据库中的章节上下文信息
        ChapterContext dbContextInfo = chapterContextDao.getById(chapterId);
        if (dbContextInfo == null || CollectionUtils.isEmpty(dbContextInfo.getModuleList())) {
            return;
        }

        // 创建模块ID到模块的映射
        Map<Long, ContextModule> dbContextMap = dbContextInfo.getModuleList()
                .stream()
                .collect(Collectors.toMap(
                        ContextModule::getId,
                        module -> module,
                        (existing, replacement) -> existing
                ));

        // 当前时间戳
        long currentTimestamp = BinaryUtils.getNumberDateTime();

        // 检查每个表格模块
        for (ContextModuleVO contextModule : tableModules) {
            // 获取数据库中对应的模块
            ContextModule dbContextData = dbContextMap.get(contextModule.getId());

            // 新增数据不处理
            if (dbContextData == null) {
                continue;
            }

            PlanTemplateChapterData moduleDefinition = contextModule.getModuleDefinition();
            Integer tableForm = moduleDefinition.getDataTableForm();

            // 根据表格类型进行不同的比较
            boolean needUpdateModifyTime = false;

            switch (tableForm) {
                case 1: // 横向表格
                    // 比对dataTableContent信息
                    if (!isEqualColumnInfo(
                            moduleDefinition.getDataTableContent(),
                            dbContextData.getModuleDefinition().getDataTableContent())) {
                        needUpdateModifyTime = true;
                    }
                    break;

                case 2: // 纵向表格
                    // 比对数据内容
                    Map<String, Object> contextData = contextModule.getData();
                    Map<String, Object> dbData = JSON.parseObject(
                            dbContextData.getData(),
                            new TypeReference<Map<String, Object>>() {});

                    if (!isEqualVerticalData(contextData, dbData)) {
                        needUpdateModifyTime = true;
                    }
                    break;

                case 3: // 矩阵表格
                    // 比对matrixRow信息
                    if (!isEqualColumnInfo(
                            moduleDefinition.getMatrixRow(),
                            dbContextData.getModuleDefinition().getMatrixRow())) {
                        needUpdateModifyTime = true;
                    }
                    break;

                default:
                    // 未知表格类型，不处理
                    continue;
            }

            // 如果内容已经不同，直接更新修改时间并继续下一个模块
            if (needUpdateModifyTime) {
                moduleDefinition.setModifyTime(currentTimestamp);
                continue;
            }

            // 比对FirstColumnWidth
            Integer contextFirstColumnWidth = moduleDefinition.getFirstColumnWidth();
            Integer dbFirstColumnWidth = dbContextData.getModuleDefinition().getFirstColumnWidth();
            if (!isEqualFirstColumnWidthAndValue(contextFirstColumnWidth, dbFirstColumnWidth)) {
                moduleDefinition.setModifyTime(currentTimestamp);
                continue;
            }

            // 比对FirstColumnWidthValue
            Integer contextFirstColumnWidthValue = moduleDefinition.getFirstColumnWidthValue();
            Integer dbFirstColumnWidthValue = dbContextData.getModuleDefinition().getFirstColumnWidthValue();
            if (!isEqualFirstColumnWidthAndValue(contextFirstColumnWidthValue, dbFirstColumnWidthValue)) {
                moduleDefinition.setModifyTime(currentTimestamp);
            }
        }
    }

    /**
     * 判断两个Map的value长度是否相同
     *
     * @param contextData 第一个Map
     * @param dbContextData 第二个Map
     * @return 如果两个Map的value长度相同返回true，否则返回false；如果都为空也返回true
     */
    private Boolean isEqualVerticalData(Map<String, Object> contextData, Map<String, Object> dbContextData) {
        // 如果两个Map都为null或都为空Map，返回true
        if ((contextData == null || contextData.isEmpty()) &&
                (dbContextData == null || dbContextData.isEmpty())) {
            return Boolean.TRUE;
        }

        // 如果只有一个Map为null或为空，返回false
        if ((contextData == null || contextData.isEmpty()) ||
                (dbContextData == null || dbContextData.isEmpty())) {
            return Boolean.FALSE;
        }

        // 获取两个Map的values集合
        Collection<Object> contextValues = contextData.values();
        Collection<Object> dbContextValues = dbContextData.values();

        // 比较两个values集合的大小是否相同
        if (contextValues.size() != dbContextValues.size()) {
            return Boolean.FALSE;
        }

        return Boolean.TRUE;
    }

    /**
     * 判断两个列表的长度和内容是否一致（不考虑顺序）
     *
     * @param contextRow 第一个列表
     * @param dbContextRow 第二个列表
     * @return 如果两个列表长度和内容一致（不考虑顺序）返回true，否则返回false；如果都为空也返回true
     */
    private Boolean isEqualColumnInfo(List<RowTableContentVo> contextRow, List<RowTableContentVo> dbContextRow) {
        // 如果两个列表都为null或都为空列表，返回true
        if ((contextRow == null || contextRow.isEmpty()) &&
                (dbContextRow == null || dbContextRow.isEmpty())) {
            return Boolean.TRUE;
        }

        // 如果只有一个列表为null或为空，返回false
        if ((contextRow == null || contextRow.isEmpty()) ||
                (dbContextRow == null || dbContextRow.isEmpty())) {
            return Boolean.FALSE;
        }

        // 检查长度是否相同
        if (contextRow.size() != dbContextRow.size()) {
            return Boolean.FALSE;
        }

        // 创建两个列表的副本，用于比较内容（不考虑顺序）
        List<RowTableContentVo> contextRowCopy = new ArrayList<>(contextRow);
        List<RowTableContentVo> dbContextRowCopy = new ArrayList<>(dbContextRow);

        return org.apache.commons.collections4.CollectionUtils.isEqualCollection(contextRowCopy, dbContextRowCopy);
    }

    private Boolean isEqualFirstColumnWidthAndValue(Integer planColumnWidth, Integer tempColumnWidth) {
        planColumnWidth = BinaryUtils.isEmpty(planColumnWidth) ? -34 : planColumnWidth;
        tempColumnWidth = BinaryUtils.isEmpty(tempColumnWidth) ? -34 : tempColumnWidth;
        if (planColumnWidth == tempColumnWidth) {
            return Boolean.TRUE;
        }
        return Boolean.FALSE;
    }


    @Override
    public Map<Long, ChapterContextVO> getChapterPointMap(List<ChapterInstance> chapterList){
        Map<Long, ChapterContextVO> result = new HashMap<>();
        if(CollectionUtils.isEmpty(chapterList)){
            return result;
        }
        Map<Long, List<ChapterInstance>> chapterGroup = chapterList.stream().collect(Collectors.groupingBy(ChapterInstance::getParentId));
        List<ChapterInstance> parentList = chapterGroup.get(0L);
        this.getChildPoint(parentList, result, chapterGroup);
        return result;
    }

    /**
     * 获取子章节上下节点信息
     */
    private void getChildPoint(List<ChapterInstance> parentList, Map<Long, ChapterContextVO> result, Map<Long, List<ChapterInstance>> chapterGroup){
        if(CollectionUtils.isEmpty(parentList)){
            return;
        }
        parentList.sort((x, y) -> {
            BigDecimal a = new BigDecimal(x.getOrderId().toString());
            BigDecimal b = new BigDecimal(y.getOrderId().toString());
            return a.compareTo(b);
        });
        for (int i = 0; i < parentList.size(); i++) {
            ChapterInstance chapter = parentList.get(i);
            ChapterContextVO point = new ChapterContextVO();
            point.setHasPrevious(i != 0);
            point.setHasNext(i < parentList.size() - 1);
            Long previousId = !point.getHasPrevious()?-1L:parentList.get(i -1).getId();
            point.setPreviousId(previousId);
            Long nextId = !point.getHasNext()? -1L:parentList.get(i + 1).getId();
            result.put(chapter.getId(), point);
            getChildPoint(chapterGroup.get(chapter.getId()), result, chapterGroup);
        }
    }
}
